<?php
    /**
    *
    */
    class Core_Model_Operationlog extends Core_Model
    {
        private $userID = 0;
        private $dirLog = '';
        private $sprlit;
        public function __construct()
        {
            parent::__construct();
            self::session();
            if (isset($_SESSION['admin']) && isset($_SESSION['admin']['UserID'])) {
                $userID = $_SESSION['admin']['UserID'];
            } else {
                //warning
                $userID = 0;
            }
            $this->userID = $userID;
            $this->dirLog = ROOT_DIR . '/asset/internal/nosql';
            if(!is_dir($this->dirLog)){
                mkdir($this->dirLog, 0777, true);
            }
            $this->sprlit = PHP_EOL . '#@---' . PHP_EOL;
            sfget_instance('Core_Base');
        }

        private function syncDir($dir)
        {
            $files = Core_IoUtils::instance()->scanDir($dir);//I/2017-05-18/08/2
            foreach ($files as $fileName) {
                $file = $dir . DS . $fileName;//I/2017-05-18/08/2/2017-05-18_08_21_10.log
                if (!is_numeric(strpos($file, '.ed'))) {
                    $flag = rename($file, $file . '.ed');
                    if ($flag) {
                        $datas = file_get_contents($file . '.ed');
                        if (!empty($datas)) {
                            $datas = explode($this->sprlit, $datas);
                            $saveDatas = array();
                            for ($i = 1, $index = count($datas); $i < $index; $i++) {
                                $data = json_decode($datas[$i], true);
                                $data['time'] = strtotime($data['CreateDate']);
                                if (!isset($saveDatas[$data['BusinessObjectTypeCode']])) {
                                    $saveDatas[$data['BusinessObjectTypeCode']] = array();
                                }
                                $saveDatas[$data['BusinessObjectTypeCode']][] = $data;
                            }
                            $results = array();
                            foreach ($saveDatas as $key => $value) {
                                $results[] = self::$nosql->batch('operationlog', DB_TABLE_PREFIX . 'operationlog_' . strtolower($key), $value);
                            }
                            $result = sfarray_true($results);
                            if ($result) {
                                rename($file . '.ed', $file . '.ed.y');
                            } else {
                                $is = 0;
                                foreach ($results as $key => $value) {
                                    if ($value) {
                                        $is ++;
                                    }
                                }
                                rename($file . '.ed', $file . '.ed.' . $is);
                            }
                        }
                    }
                }
            }
        }
        public function sync($time = null)
        {
            if (!self::$nosql->isEnable()) {
                return false;
            }
            $dirs = Core_IoUtils::instance()->scanDir($this->dirLog);
            foreach ($dirs as $dirType) {
                if (empty($time)) {
                    //全部扫描
                    $dirDs = Core_IoUtils::instance()->scanDir($this->dirLog . DS . $dirType);//I
                    foreach ($dirDs as $dirD) {
                        $dirHs = Core_IoUtils::instance()->scanDir($this->dirLog . DS . $dirType . DS . $dirD);//I/2017-05-18
                        foreach ($dirHs as $dirH) {
                            $dirIs = Core_IoUtils::instance()->scanDir($this->dirLog . DS . $dirType . DS . $dirD . DS . $dirH);//I/2017-05-18/08
                            foreach ($dirIs as $dirI) {
                                $this->syncDir($this->dirLog . DS . $dirType . DS . $dirD . DS . $dirH . DS . $dirI);
                            }
                        }
                    }
                } else {
                    //局部日期时间扫描
                    $dir = $this->dirLog . DS . $dirType . DS . date('Y-m-d/H/', $time) . (int)(date('i', $time) / 10);
                    $this->syncDir($dir);
                }
            }
            return 'ok';
        }

        private function appendOperationlog($type, $data)
        {
            list($usec, $sec)   =   explode(' ', microtime());
            $data['_i'] = $sec + $usec;
            $data['_i'] = explode('.', $data['_i']);
            $data['_i'][1] = sprintf('%04s', $data['_i'][1]);
            $data['_i'] = implode('', $data['_i']);
            $time = time();
            $dirLog = $this->dirLog;
            $dirLog = $dirLog . DS . $type . DS . date('Y-m-d', $time) . DS . date('H', $time) . DS . (int)(date('i', $time) / 10);
            if(!is_dir($dirLog)){
                mkdir($dirLog, 0777, true);
            }
            $fileName = ip2long(FUNC_IP) . '_' . date('Y-m-d_H_i_s', $time) . '.log';
            $file = $dirLog . DS . $fileName;
            file_put_contents($file, $this->sprlit . json_encode($data), FILE_APPEND);
            if (DEV_MODE == 1) {
                $this->sync(time());
            }
        }

        public function queryOperationlog($param = array())
        {
            if (!sfget_valid_one($param, array('type'))) {
                return array();
            } else {
                if (is_array($param['type']) && count($param['type']) == 1) {
                    $param['type'] = current($param['type']);
                }
                if (is_array($param['code']) && count($param['code']) == 1) {
                    $param['code'] = current($param['code']);
                }
            }
            $tbl = DB_TABLE_PREFIX . 'operationlog_' . strtolower($param['type']);
            $getParam = array('limit' => 50, 'where' => array('AND' => array()));
            if (!empty($param['code'])) {
                $getParam['where']['AND']['BusinessObjectCode'] = $param['code'];
            }
            if (!empty($param['level'])) {
                $getParam['where']['AND']['OperationLogTypeCode'] = $param['level'];
            }
            if (!empty($param['content'])) {
                $getParam['where']['AND']['Content'] = $param['content'];
            }
            if (!empty($param['data'])) {
                $getParam['where']['AND']['Data'] = $param['data'];
            }
            $datas = self::$nosql->get('operationlog', $tbl, $getParam);
            $fDatas = array();
            foreach ($datas as $key => $value) {
                $fDatas[$value['_i']] = $value;
            }
            krsort($fDatas);
            return array_merge($fDatas);
        }
        public function queryOperationlogTotal($param = array())
        {
            if (!sfget_valid_one($param, array('type'))) {
                return 0;
            }
            return self::$nosql->getLastTotal();
        }

        public function insertOperationlog($type, $id, $content, $data = '', $userID = null, $level = 'W')
        {
            if ($userID === null) {
                $userID = $this->userID;
            }
            $bind = array(
                'BusinessObjectTypeCode' => $type
                , 'OperationLogTypeCode' => strtoupper($level)
                , 'BusinessObjectCode' => $id
                , 'Content' => $content
                , 'UserID' => $userID
                , 'CreateDate' => date('Y-m-d H:i:s')
                , 'IP' => FUNC_IP
            );
            if (!empty($data)) {
                if (is_array($data) || is_object($data)) {
                    $bind['Data'] = serialize($data);
                } else {
                    $bind['Data'] = $data;
                }
            }
            return $this->appendOperationlog($type, $bind);
        }
        public function saveOperationlog($type, $id, $content, $data = '', $userID = null, $level = 'W')
        {
            if ($userID === null) {
                $userID = $this->userID;
            }
            $bind = array(
                'BusinessObjectTypeCode' => $type
                , 'OperationLogTypeCode' => strtoupper($level)
                , 'BusinessObjectCode' => $id
                , 'Content' => $content
                , 'UserID' => $userID
                , 'IP' => FUNC_IP
            );
            if (!empty($data)) {
                if (is_array($data) || is_object($data)) {
                    $bind['Data'] = serialize($data);
                } else {
                    $bind['Data'] = $data;
                }
            }
            $bind['save'] = 1;
            return $this->appendOperationlog($type, $bind);
            /*
            $tbl = DB_TABLE_PREFIX . 'operationlog_' . strtolower($type);
            $wheres = array('query' => array('bool' => array('must' => array())));
            foreach ($bind as $key => $value) {
                if ($key != 'Data') {
                    $wheres['query']['bool']['must'][] = array('match' => array($key => $value));
                }
            }
            $bind['CreateDate'] = date('Y-m-d H:i:s');
            $oldDatas = self::$nosql->get('operationlog', $tbl, array('limit' => 1, 'args' => array('body' => $wheres)));
            if (empty($oldDatas)) {
                self::$nosql->add('operationlog', $tbl, $bind);
            } else {
                self::$nosql->del('operationlog', $tbl, $oldDatas[0]['__']['_id']);
                self::$nosql->add('operationlog', $tbl, $bind);
            }
            return true;
            */
        }

        private function createOperationlogTable($type) {
            $tbl = DB_TABLE_PREFIX . 'operationlog_' . strtolower($type);
            $sql = "CREATE TABLE IF NOT EXISTS `" . $tbl . "` (`OperationLog` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '操作日志ID，从1开始累计',`BusinessObjectTypeCode` varchar(3) NOT NULL COMMENT '业务对象类型代码，取自BusinessObjectType表',`OperationLogTypeCode` varchar(2) NOT NULL,`BusinessObjectCode` varchar(300) DEFAULT NULL,`Content` varchar(300) NOT NULL COMMENT '操作内容',`Data` text,`CreateDate` datetime NOT NULL COMMENT '创建日期',`UserID` int(11) NOT NULL COMMENT '创建人用户ID',`IP` varchar(39) NOT NULL,PRIMARY KEY (`OperationLog`),KEY `OperationLogTypeCode` (`OperationLogTypeCode`,`BusinessObjectCode`)) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COMMENT='操作日志表，记录系统内部操作的过程' AUTO_INCREMENT=1;";
            return $this->db->exec($sql);
        }

        public function insertOperationlogDB($type, $id, $content, $data = '', $userID = null, $level = 'W')
        {
            if ($userID === null) {
                $userID = $this->userID;
            }
            $bind = array(
                'BusinessObjectTypeCode' => $type
                , 'OperationLogTypeCode' => strtoupper($level)
                , 'BusinessObjectCode' => $id
                , 'Content' => $content
                , 'UserID' => $userID
                , 'CreateDate' => new Zend_Db_Expr('NOW()')
                , 'IP' => FUNC_IP
            );
            if (!empty($data)) {
                if (is_array($data) || is_object($data)) {
                    $bind['Data'] = serialize($data);
                } else {
                    $bind['Data'] = $data;
                }
            }
            $tbl = DB_TABLE_PREFIX . 'operationlog_' . strtolower($type);
            try {
                return $this->db->insert($tbl, $bind);
            } catch (Exception $e) {
                $this->createOperationlogTable($type);
                return $this->db->insert($tbl, $bind);
            }
            return $this->setError('找不到日志表');
        }
        public function saveOperationlogDB($type, $id, $content, $data = '', $userID = null, $level = 'W')
        {
            if ($userID === null) {
                $userID = $this->userID;
            }
            $bind = array(
                'BusinessObjectTypeCode' => $type
                , 'OperationLogTypeCode' => strtoupper($level)
                , 'BusinessObjectCode' => $id
                , 'Content' => $content
                , 'UserID' => $userID
                , 'IP' => FUNC_IP
            );
            if (!empty($data)) {
                if (is_array($data) || is_object($data)) {
                    $bind['Data'] = serialize($data);
                } else {
                    $bind['Data'] = $data;
                }
            }
            $where = '';
            foreach ($bind as $key => $value) {
                if ($key != 'Data') {
                    $where .= ' and ' . $this->db->quoteInto($key . ' = ?', $value);
                }
            }
            if (!empty($where)) {
                $where = substr($where, 4);
            }
            $tbl = DB_TABLE_PREFIX . 'operationlog_' . strtolower($type);
            $base = $this->db->select()->from($tbl)->where($where)->limit(1);
            $row = $this->db->fetchRow($base);
            $bind['CreateDate'] = new Zend_Db_Expr('NOW()');
            if (empty($row)) {
                try {
                    return $this->db->insert($tbl, $bind);
                } catch (Exception $e) {
                    $this->createOperationlogTable($type);
                    return $this->db->insert($tbl, $bind);
                }
            } else {
                if ($row['Data'] == $bind['Data']) {
                    try {
                        return $this->db->update($tbl, array('CreateDate' => new Zend_Db_Expr('NOW()')), $this->db->quoteInto('OperationLog = ?', $row['OperationLog']));
                    } catch (Exception $e) {
                        return $this->setError('找不到日志表！');
                    }
                } else {
                    try {
                        return $this->db->insert($tbl, $bind);
                    } catch (Exception $e) {
                        $this->createOperationlogTable($type);
                        return $this->db->insert($tbl, $bind);
                    }
                }
            }
        }
    }